package com.classnet;

import com.classnet.db.*;
import com.classnet.mail.MailMessage;
import com.classnet.mail.PostMan;
import com.classnet.mail.PostManResult;
import java.util.Properties;
import java.util.Random;
import java.util.ResourceBundle;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 *
 * @author karltinawi
 * @version 1.0
 */
public class ClassNet {
    
    private ResourceBundle rs;
    private EntityManagerFactory emf;
    private CnetSession session;
    
    public ClassNet() {
        rs = ResourceBundle.getBundle("com.classnet.ClassNet");
        emf = Persistence.createEntityManagerFactory("classnetPU");
        session = new CnetSession(getEntityManager());
    }
    
    private EntityManager getEntityManager() {
        return emf.createEntityManager();
    }
    
    private User findUser(String username) {
        return (User) session.find(User.class, username);
    }
    
    private PostManResult post(String to, String subject, String message) {
        Properties props = System.getProperties();
        props.put("postman.post.debug", rs.getString("post.debug"));
        props.put("mail.smtp.host", rs.getString("post.host"));
        props.put("mail.smtp.port", rs.getString("post.port"));
        props.put("mail.smtp.auth", rs.getString("post.auth"));
        props.put("mail.smtp.starttls.enable", rs.getString("post.auth"));
        
        Authenticator auth = new Authenticator() {
            @Override
            public PasswordAuthentication getPasswordAuthentication() {
                String user = rs.getString("post.username");
                String pass = rs.getString("post.password");
                return new PasswordAuthentication(user, pass);
            }
        };
        
        MailMessage mm = null;
        try {
            mm = new MailMessage(new InternetAddress(
                    rs.getString("post.username")),
                    new InternetAddress[] {new InternetAddress(to)});
            
            mm.setSubject(subject);
            mm.setMessage(message);
            return PostMan.post(mm, props, auth);
        }
        catch(AddressException ex) {
            return new PostManResult(PostManResult.POST_FAIL, ex.getMessage(), mm);
        }
    }
    
    public void requestAccount(User user) {        
        if(user == null)
            throw new NullPointerException("Failed to request Account. User Expected.");
        if(findUser(user.getEmail()) != null)
            throw new IllegalArgumentException("Account " + user.getEmail() + " already exists.");
        
        //Check if a code has previously been created, if so, use that code, and
        //if not then generate and send a new one.
        AccRequest requestAcc = session.getEntityManager().find(AccRequest.class, user.getEmail());
        if(requestAcc == null) {
            Random random = new Random();
            String code = "";
            
            for(int i = 0; i < 5; i ++) {
                int next = random.nextInt(25) + 97;
                code += (char) next;
            }            
            
            requestAcc = new AccRequest(user.getEmail(), code);
            session.persist(requestAcc);
        }        
        
        //E-mail the code to the user
        post(user.getEmail(), "Confirm E-mail", requestAcc.getCode());
    }
    
    public void createAccount(User user, String code) {
        if(user == null)
            throw new NullPointerException("Failed to create Account. User Expected.");
        if(code == null)
            throw new NullPointerException("Failed to create Account. Code Expected.");
        
        if(findUser(user.getEmail()) != null)
            throw new IllegalArgumentException("Account " + user.getEmail() + " already exists.");
        
        AccRequest requestAcc = session.getEntityManager().find(AccRequest.class, user.getEmail());
        
        if(requestAcc == null) 
            throw new IllegalArgumentException("Account has not been requested for " + user.getEmail());
        else if(!code.equals(requestAcc.getCode()))
            throw new IllegalArgumentException("Code is not valid.");
        
        Profile profile = new Profile(user.getEmail());
        user.setProfile(profile);
        
        session.persist(user);
        session.persist(profile);
        session.remove(requestAcc);
        
        String title = "Welcome to classNet";
        String message = "Thank you for joining classNet!\n\n" +
                "Here are your login details, just in-case...\n\n" +
                "Username: " + user.getEmail() + "\n" +
                "Password: " + new String(user.getPassword()) + "\n\n" +
                "We hope you enjoy using classNet, and don't forget that you can" +
                " email us with comments at: " + rs.getString("post.username") + "\n\n" +
                "The classNet Team.";
        
        post(user.getEmail(), title, message);
    }
    
    public CnetUserSession login(String username, byte[] password) {
        User user = findUser(username);
        if(user == null)
            throw new IllegalArgumentException("Account " + username + " does not exist.");
        
        if(new String(user.getPassword()).equals(new String(password)))
            return new CnetUserSession(getEntityManager(), user);
        
        throw new IllegalArgumentException("Invalid Password for account " + username);
    }
}